﻿using Microsoft.Owin.Security;
using Newtonsoft.Json.Linq;
using System;

namespace Sustainalytics.OAuth.Services.Common.Client
{
    public class OAuthTokenResponse
    {
        /// <summary>
        /// Token content.
        /// </summary>
        public string Content { get; set; }

        /// <summary>
        /// Token as JSON object.
        /// </summary>
        public JObject JObject { get; private set; }

        /// <summary>
        /// Token type. Eg: Bearer
        /// http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-7.1
        /// </summary>
        public string TokenType { get; private set; }

        /// <summary>
        /// Access token.
        /// </summary>
        public string AccessToken { get; private set; }

        /// <summary>
        /// Refresh token.
        /// </summary>
        public string RefreshToken { get; private set; }

        /// <summary>
        /// Refresh time expires after the given timespan.
        /// </summary>
        public TimeSpan AccessTokenExpirationTime { get; private set; }

        /// <summary>
        /// Error message if there is an error.
        /// </summary>
        public string Error { get; private set; }

        /// <summary>
        /// Determine if is an error.
        /// </summary>
        public bool IsError { get; private set; }


        /// <summary>
        /// Ctor.
        /// </summary>
        /// <param name="content"> Token as JSON string. </param>
        public OAuthTokenResponse(string content)
        {
            this.Content = content;

            // parse content and extract information
            ParseContent(content);
        }

        /// <summary>
        /// Parse response content.
        /// </summary>
        /// <param name="content"> Response content. </param>
        private void ParseContent(string content)
        {
            this.JObject = JObject.Parse(content);

            ParseTokenType();
            ParseAccessToken();
            ParseRefreshToken();
            ParseAccessTokenExpirationTime();
        }

        /// <summary>
        /// Parse token type.
        /// </summary>
        private void ParseTokenType()
        {
            JToken tokenType = this.JObject["token_type"];

            if (tokenType != null)
            {
                this.TokenType = tokenType.ToString();
            }
        }

        /// <summary>
        /// Parse access token.
        /// </summary>
        private void ParseAccessToken()
        {
            JToken accessToken = this.JObject["access_token"];

            if (accessToken != null)
            {
                this.AccessToken = accessToken.ToString();
            }
            else
            {
                JToken err = this.JObject["error"];

                if (err != null)
                {
                    this.Error = err.ToString();
                }

                this.IsError = true;
            }
        }

        /// <summary>
        /// Parse refresh token.
        /// </summary>
        private void ParseRefreshToken()
        {
            JToken refreshToken = this.JObject["refresh_token"];

            if (refreshToken != null)
            {
                this.RefreshToken = refreshToken.ToString();
            }
        }

        /// <summary>
        /// Parse access token expiration time.
        /// </summary>
        private void ParseAccessTokenExpirationTime()
        {
            JToken expiresIn = this.JObject["expires_in"];

            if (expiresIn != null)
            {
                this.AccessTokenExpirationTime = TimeSpan.FromSeconds(expiresIn.ToObject<int>());
            }
        }


        /// <summary>
        /// Unprotect and deserialize access token into AuthenticationTicket.
        /// </summary>
        /// <param name="secureDataFormat"> Object used to protect and unprotect the authentication ticket. </param>
        /// <returns> Authentication ticket. </returns>
        public AuthenticationTicket GetAuthenticationTicket(ISecureDataFormat<AuthenticationTicket> secureDataFormat)
        {
            if (this.IsError)
                return null;

            // unprotect and deserialize AuthenticationTicket
            AuthenticationTicket ticket = secureDataFormat.Unprotect(this.AccessToken);

            return ticket;
        }
    }
}
